<head>
    <meta charset="UTF-8">
    <!-- import CSS -->
    <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
</head>
<style>
    #canvas {
        position: absolute;
        /*定位*/
        top: 50px;
        left: 240px;
        width: 750px;
        height: 750px;
        border: thin dotted #FF0000;
        border-bottom: none;
    }

    .box {
        position: absolute;
        /*定位*/
        top: 0px;
        left: 0px;
        width: 200px;
        height: 200px;
        background: #666;
        user-select: none;
        background-repeat: no-repeat;
        background-size: cover;
        /*设置一下背景*/
    }

    .coor {
        width: 10px;
        height: 10px;
        overflow: hidden;
        cursor: se-resize;
        position: absolute;
        right: 0;
        bottom: 0;
        background-color: red;
    }

    .icon {
        font-size: 40px;
    }

    #app {
        margin-top: 20px;
    }

    .left-aside {
        height: 800px;
        background-color: #fff;
        /* border: thin dotted #FF0000; */
    }

    .product-container {
        height: 226px;
        border: thin dotted #CCC;
        text-align: center;
    }

    .product-container-icon {
        font-size: 190px;
    }
</style>

<body>
    <div id="app">
        <el-container>
            <el-aside width="230px" class="left-aside">
                <el-button style="width:100px" @click="addBox('image')">
                    <div class="demo-basic--circle">
                        <i class="el-icon-picture icon"> </i>
                    </div>
                    图片
                </el-button>
                <el-button style="width:100px" @click="addBox('product')">
                    <div class="demo-basic--circle">
                        <i class="el-icon-picture icon"> </i>
                    </div>
                    <span>产品</span>
                </el-button>
            </el-aside>
            <el-aside width="800px">
                <div id="canvas" :model="canvas"
                    :style="{backgroundColor: form.bgItem.color,height:form.bgItem.height}">
                    <div v-for="(item, index) in form.nodeItem" :key="index">
                        <!-- 图片 -->
                        <div v-if="item.type=='image'" class="box" v-drag="changeBox" :data-index="index"
                            @click="clickBox(item.nodeIndex)"
                            :style="{width: item.width + 'px', height: item.height + 'px',top:item.top +'px',left:item.left +'px',backgroundImage:item.src ? 'url('+item.src+')' : '',zIndex:item.zIndex}">
                            <!--实现用指令形式实现拖拽效果-->
                            <div class="coor" v-move='changeBox' @mousedown.stop>

                            </div>
                            node{{item.nodeIndex}}
                        </div>
                        <!-- 产品 -->
                        <div v-if="item.type=='product'" class="box" v-drag="changeBox" :data-index="index"
                            @click="clickBox(item.nodeIndex)" style="background:none"
                            :style="{width: item.width + 'px', height: item.height + 'px',top:item.top +'px',left:item.left +'px',zIndex:item.zIndex}">
                            <el-container>
                                <el-aside width="50%" class="product-container">
                                    <div class="demo-basic--circle">
                                        <i class="el-icon-picture icon product-container-icon"> </i>
                                    </div>
                                    node{{item.nodeIndex}}
                                </el-aside>
                                <el-aside width="50%" class="product-container">
                                    <div class="demo-basic--circle">
                                        <i class="el-icon-picture icon product-container-icon"> </i>
                                    </div>
                                    node{{item.nodeIndex}}
                                </el-aside>
                            </el-container>
                        </div>
                    </div>
                </div>
            </el-aside>
            <el-aside width="300px">
                <el-form ref="form" :inline="true" :model="form" label-width="80px">
                    <el-form-item label="背景颜色">
                        <el-color-picker v-model="form.bgItem.color" show-alpha></el-color-picker>
                        <div v-show='false'>
                            <el-input size="mini" v-model="form.bgItem.color">
                            </el-input>
                        </div>
                    </el-form-item>
                    <el-form-item label="背景高度" size="mini">
                        <el-input-number size="mini" v-model="form.bgItem.height" :min=500 controls-position="right">
                        </el-input-number>
                    </el-form-item>
                    <el-divider></el-divider>
                    <div v-for="(item, index) in form.nodeItem" :key="index">
                        <div v-if="item.nodeIndex == moveIndex">
                            <el-tag>node{{item.nodeIndex}}属性设置</el-tag>
                            <br /><br />
                            <div v-show='false'>
                                <el-input size="mini" v-model="item.type">
                                </el-input>
                            </div>

                            <!-- 图片可以设置宽高 -->
                            <div v-if="attribute[item.type].width > 0 || attribute.common.width > 0">
                                <el-form-item label="宽" size="mini">
                                    <el-input-number size="mini" v-model="item.width" :min=30 controls-position="right"
                                        @change="changeWidthOrLeft(item,index,'width')">
                                    </el-input-number>
                                </el-form-item>
                            </div>
                            <div v-if="attribute[item.type].height > 0 || attribute.common.height > 0">
                                <el-form-item label="高" size="mini">
                                    <el-input-number size="mini" v-model="item.height" :min=30
                                        controls-position="right">
                                    </el-input-number>
                                </el-form-item>
                            </div>
                            <div v-if="attribute[item.type].src > 0 || attribute.common.src > 0">
                                <el-form-item label="图片地址" size="mini">
                                    <el-input size="mini" v-model="item.src">
                                    </el-input>
                                </el-form-item>
                            </div>
                            <div v-if="attribute[item.type].href > 0 || attribute.common.href > 0">
                                <el-form-item label="跳转链接" size="mini">
                                    <el-input size="mini" v-model="item.href">
                                    </el-input>
                                </el-form-item>
                            </div>
                            <!-- 产品信息 -->
                            <div v-if="attribute[item.type].info > 0 || attribute.common.info > 0">
                                <el-form-item label="产品id" size="mini">
                                    <el-input type="textarea" size="mini" v-model="item.info"
                                        placeholder="请输入产品id,','隔开">
                                        </el-input-text>
                                </el-form-item>
                            </div>

                            <!-- 相对定位 -->
                            <div v-if="attribute[item.type].element > 0 || attribute.common.element > 0">
                                <el-form-item label="定位元素" size="mini">
                                    <el-select v-model="item.element" @change="changeElement(index)">
                                        <el-option value="body"></el-option>
                                        <el-option v-for="options in form.nodeItem" :key="options.nodeIndex"
                                            :label="'node'+options.nodeIndex" :value="options.nodeIndex"
                                            v-if="item.nodeIndex != options.nodeIndex">
                                        </el-option>
                                    </el-select>
                                </el-form-item>
                            </div>
                            <div v-if="attribute[item.type].position > 0 || attribute.common.position > 0">
                                <el-form-item label="定位位置" size="mini">
                                    <el-select v-model="item.position" @change="changePosition(index)">
                                        <el-option v-for="options in position" :key="options.index"
                                            :label="options.option" :value="options.value">
                                        </el-option>
                                    </el-select>
                                </el-form-item>
                            </div>
                            <div v-if="attribute[item.type].positionX > 0 || attribute.common.positionX > 0 ">
                                <el-form-item label="X" size="mini">
                                    <el-input-number size="mini" v-model="item.positionX"
                                        @change="changePosition(index,'getTopAndLeft')" controls-position="right">
                                    </el-input-number>
                                </el-form-item>
                            </div>
                            <div v-if="attribute[item.type].positionY > 0 ||  attribute.common.positionY > 0">
                                <el-form-item label="Y" size="mini">
                                    <el-input-number size="mini" v-model="item.positionY"
                                        @change="changePosition(index,'getTopAndLeft')" controls-position="right">
                                    </el-input-number>
                                </el-form-item>
                            </div>
                            <div v-if="attribute[item.type].zIndex > 0 ||  attribute.common.zIndex > 0">
                                <el-form-item label="层级" size="mini">
                                    <el-input-number size="mini" v-model="item.zIndex" :min="0" :max="99999"
                                        controls-position="right">
                                    </el-input-number>
                                </el-form-item>
                            </div>
                            <br />
                            <el-button type="danger" icon="el-icon-delete" @click="deleteItem(index)">
                                删除
                            </el-button>
                        </div>
                    </div>
                </el-form>
            </el-aside>
        </el-container>
        <el-button type="primary" @click="onSubmit">立即创建</el-button>
        <el-button type="" @click="onResert">重置</el-button>
    </div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="https://cdn.bootcss.com/qs/6.5.1/qs.min.js"></script>
<script>
    //main.js
    let app = new Vue({
        el: '#app',
        data() {
            return {
                //提交到后台的信息
                form: {
                    bgItem: {
                        type: 'bg',
                        color: '',
                        height: 750,
                    },
                    nodeItem: [],
                },
                //图片组件
                imageItem: {
                    width: 300,
                    height: 300,
                    top: 0,
                    left: 0,
                    nodeIndex: 0,
                    type: 'image',
                    src: '',
                    href: '',
                    element: 'body',        //相对元素
                    oldElement: 'body',     //上次对应的元素,防止相对元素改变错误时，不能恢复到上一次
                    position: 1,            //相对位置:1左上,2左下,3右上,4右下
                    positionX: 0,
                    positionY: 0,
                    zIndex: 0,
                },
                //产品组件
                productItem: {
                    width: 750,
                    height: 226,
                    top: 0,
                    left: 0,
                    nodeIndex: 0,
                    type: 'product',
                    info: '',               //产品信息
                    element: 'body',        //相对元素
                    oldElement: 'body',     //上次对应的元素,防止相对元素改变错误时，不能恢复到上一次
                    position: 1,            //相对位置:1左上,2左下,3右上,4右下
                    positionX: 0,
                    positionY: 0,
                    zIndex: 0,
                },
                //定位相关(select下拉框需要)
                position: [{
                    option: '左上',
                    value: 1,
                }, {
                    option: '左下',
                    value: 2,
                }, {
                    option: '右上',
                    value: 3,
                }, {
                    option: '右下',
                    value: 4,
                }],
                nodeIndex: 0,           //节点(绑定相对元素需要)
                moveIndex: 0,           //正在移动的节点
                nodeItem: [],           //以nodeIndex 为key 的节点数组(查找相对位置是否有闭环的时候需要)
                //判断是否可以设置属性设置时用到
                attribute: {
                    //公共属性
                    common: {
                        top: 1,
                        element: 1,
                        position: 1,
                        positionX: 1,
                        positionY: 1,
                        zIndex: 1,
                    },
                    //图片组件独有属性
                    image: {
                        width: 1,
                        height: 1,
                        left: 1,
                        src: 1,
                        href: 1,
                    },
                    //产品组件独有属性
                    product: {
                        info: 1,               //产品信息
                    },
                }
            }
        },
        created() {
            // let that = this
            // axios.get('http://php7.com/drag/demo3/getinfo.php').then(function (response) {
            //     if (response.data) {
            //         that.form = response.data;
            //         //循环
            //         that.form.nodeItem.forEach((item, i) => {
            //             //以节点为key,对应值为value
            //             that.nodeIndex = item.nodeIndex
            //             that.$set(that.nodeItem, that.nodeIndex, item)
            //         })
            //     }
            // })

            // 后台用到数据
            // const loading = this.$loading({
            //     lock: true,
            //     text: '数据加载中',
            //     spinner: 'el-icon-loading',
            //     background: 'rgba(0, 0, 0, 0.7)'
            // });
            // let that = this
            // axios.get('/customactivity/template?getinfo=1&custom_activity_id=' + <? php echo $_GET['custom_activity_id'] ?>).then(function (response) {
            //     if (response.data) {
            //         that.form = response.data.data;
            //         //循环
            //         that.form.nodeItem.forEach((item, i) => {
            //             //以节点为key,对应值为value
            //             that.nodeIndex = item.nodeIndex
            //             that.$set(that.nodeItem, that.nodeIndex, item)
            //         })
            //         loading.close();
            //     }
            // })
        },
        methods: {
            addBox(type) {
                //节点数+1
                this.nodeIndex++;
                //组件类型
                let typeItem = type + 'Item'
                //组件填充
                this.form.nodeItem.push({ ...this[typeItem] })
                //获取数组key
                let key = this.form.nodeItem.length - 1
                //当前节点
                this.moveIndex = this.form.nodeItem[key]['nodeIndex'] = this.nodeIndex
                //以节点为key,对应值为value
                this.$set(this.nodeItem, this.nodeIndex, this.form.nodeItem[key])
            },

            //删除节点
            deleteItem(index) {
                this.form.nodeItem.splice(index, 1)
            },
            //点击节点
            clickBox(nodeIndex) {
                this.moveIndex = nodeIndex
            },
            //提交
            onSubmit() {
                let data = JSON.stringify(this.form)
                window.open("http://php7.com/drag/demo3/show.php?data=" + data, '_blank');

                //后台提交用到
                // let custom_activity_id = "<?php echo $_GET['custom_activity_id'] ?>";
                // let that = this
                // axios.post("/customactivity/templatesave",
                //     Qs.stringify({
                //         "custom_activity_id": custom_activity_id,
                //         "form": JSON.stringify(that.form)
                //     })
                // ).then(res => {
                //     if (res.data.status == 1) {
                //         this.$notify({
                //             title: 'ok',
                //             message: res.data.msg,
                //             type: 'success'
                //         });
                //     } else {
                //         this.$notify({
                //             title: '错误',
                //             message: res.data.msg,
                //             type: 'danger'
                //         });
                //     }
                // })
            },
            //重置
            onResert() {
                this.$confirm('重置后不可恢复，是否确认重置？', '确认信息', {
                    distinguishCancelAndClose: true,
                    confirmButtonText: '确认',
                    cancelButtonText: '取消'
                })
                    .then(() => {
                        Object.assign(this.$data, this.$options.data())
                    })
            },

            //更改宽/左的时候判断，不能超过框
            changeWidthOrLeft(e, index, changeType) {
                this.changeBox({
                    width: e.width,
                    height: e.height,
                    left: e.left,
                    top: e.top,
                    type: e.type + 'Item',       //imageItem
                    index: index,      //0
                    changeType: changeType
                })
            },
            //更改box 坐标/大小
            changeBox(e) {
                let index = e.index
                let node = this.form.nodeItem[index]
                if (e.changeType == 'width') {
                    if (e.width + e.left >= 750) {
                        e.width = 750 - e.left
                        console.log(e.width)
                    }
                } else if (e.changeType == 'left') {
                    if (e.width + e.left >= 750) {
                        e.left = 750 - e.width
                    }
                }
                node.width = e.width
                node.height = e.height
                node.left = e.left
                node.top = e.top
                this.changePosition(index, 'getPositionXY')
                //更新相关联的节点的X、Y
                this.changeRelationPosition(node.nodeIndex)
            },

            /***********************更改相对定位相关*********************/
            changeElement(index) {
                //判断element是否可以绑定
                let node = this.form.nodeItem[index]
                let nodeIndex = node.nodeIndex
                while (node.element != 'body') {
                    if (node.element == nodeIndex) {
                        this.$notify({
                            title: '错误',
                            message: '绑定定位元素错误',
                            type: 'danger'
                        });
                        //存在闭环,跳出
                        this.form.nodeItem[index].element = this.form.nodeItem[index].oldElement
                        return;
                    }
                    node = this.nodeItem[node.element]
                }
                this.form.nodeItem[index].oldElement = this.form.nodeItem[index].element
                this.changePosition(index)
            },
            //更改与此节点绑定的所有节点的X/Y位置
            changeRelationPosition(nodeIndex) {
                this.form.nodeItem.forEach((item, i) => {
                    if (item.element == nodeIndex) {
                        this.changePosition(i)
                    }
                })
            },
            // 更改定位位置(根据定位元素/定位位置/top/left 确定 /X/Y )
            changePosition(index, type = 'getPositionXY') {
                //节点
                let node = this.form.nodeItem[index]
                let left, right, top, down = 0
                if (node.element == 'body') {
                    //左
                    left = 0
                    //下
                    down = this.form.bgItem.height
                    //上
                    top = 0
                    //右
                    right = 750
                } else {
                    //定位元素的节点信息
                    let elementNode = this.nodeItem[node.element]
                    //左
                    left = elementNode.left
                    //下
                    down = elementNode.top + elementNode.height
                    //上
                    top = elementNode.top
                    //右
                    right = elementNode.left + elementNode.width
                }
                //根据定位元素/定位位置/top/left 确定 /X/Y 
                if (type == "getTopAndLeft") {
                    switch (node.position) {
                        // 相对位置:1左上,2左下,3右上,4右下
                        case 1: //1左上
                            //防止出框做判断
                            node.positionY = top + node.positionY > 0 ? node.positionY : -top
                            node.positionX = left + node.positionX > 0 ? node.positionX : -left
                            node.top = top + node.positionY
                            node.left = left + node.positionX
                            break;
                        case 2: //2左下
                            //防止出框做判断
                            node.positionY = down - node.positionY > 0 ? node.positionY : -down
                            node.positionX = left + node.positionX > 0 ? node.positionX : -left

                            node.top = down + node.positionY
                            node.left = left + node.positionX
                            break;
                        case 3: //3右上
                            //防止出框做判断
                            node.positionY = top + node.positionY > 0 ? node.positionY : -top
                            node.positionX = right - node.positionX > 0 ? node.positionX : -right

                            node.top = top + node.positionY
                            node.left = right + node.positionX
                            break;
                        case 4:
                            //防止出框做判断
                            node.positionY = down + node.positionY > 0 ? node.positionY : -down
                            node.positionX = right + node.positionX > 0 ? node.positionX : -right

                            node.top = down + node.positionY
                            node.left = right + node.positionX
                            break;
                    }
                    //更新相关联的节点的X、Y
                    this.changeRelationPosition(node.nodeIndex)
                } else if (type == "getPositionXY") {
                    switch (node.position) {
                        // 相对位置:1左上,2左下,3右上,4右下
                        case 1:
                            node.positionY = node.top - top
                            node.positionX = left - node.left
                            break;
                        case 2:
                            node.positionY = node.top - down
                            node.positionX = left - node.left
                            break;
                        case 3:
                            node.positionY = node.top - top
                            node.positionX = node.left - right
                            break;
                        case 4:
                            node.positionY = node.top - down
                            node.positionX = node.left - right
                            break;
                    }
                }
            },
            /***********************更改相对定位相关*********************/
        },
        //拖拽相关
        directives: {
            //拖动框
            drag: {
                // 指令的定义
                bind: function (el, value) {
                    let odiv = el;   //获取当前元素
                    odiv.onmousedown = (e) => {
                        let index = e.currentTarget.getAttribute('data-index')

                        //算出鼠标相对元素的位置
                        let disX = e.clientX - odiv.offsetLeft;
                        let disY = e.clientY - odiv.offsetTop;
                        document.onmousemove = (e) => {
                            //用鼠标的位置减去鼠标相对元素的位置，得到元素的位置
                            let left = e.clientX - disX < 0 ? 0 : e.clientX - disX;
                            let top = e.clientY - disY < 0 ? 0 : e.clientY - disY;
                            let width = odiv.offsetWidth
                            let height = odiv.offsetHeight

                            if (typeof value.value === 'function') {
                                value.value({
                                    width: width,
                                    height: height,
                                    left: left,
                                    top: top,
                                    index: index,      //0
                                    changeType: 'left'
                                })
                            }
                        };
                        document.onmouseup = (e) => {
                            document.onmousemove = null;
                            document.onmouseup = null;
                        };
                        //防止鼠标出现禁止符合(优化)
                        document.ondragenter = (e) => {
                            e.preventDefault()
                        }
                        document.ondragover = (e) => {
                            e.preventDefault()
                        }
                    };
                }
            },
            //拖动角标
            move: {
                // 指令的定义
                bind: function (el, value) {
                    let odiv = el;   //获取当前元素
                    odiv.onmousedown = (e) => {
                        //算出鼠标相对元素的位置
                        let disX = e.clientX - odiv.offsetLeft;
                        let disY = e.clientY - odiv.offsetTop;
                        let parentNode = e.currentTarget.parentElement;

                        document.onmousemove = (e) => {
                            //用鼠标的位置减去鼠标相对元素的位置，得到元素的位置
                            let left = e.clientX - disX < 20 ? 20 : e.clientX - disX;
                            let top = e.clientY - disY < 20 ? 20 : e.clientY - disY;

                            if (typeof value.value === 'function') {
                                value.value({
                                    width: left + 10,
                                    height: top + 10,
                                    left: parentNode.offsetLeft,
                                    top: parentNode.offsetTop,
                                    type: parentNode.getAttribute('data-form'),       //imageItem
                                    index: parentNode.getAttribute('data-index'),      //0
                                    changeType: 'width'
                                })
                            }
                        };
                        document.onmouseup = (e) => {
                            document.onmousemove = null;
                            document.onmouseup = null;
                        };
                    };
                }
            }
        }
    });
</script>